﻿using System.Collections.Generic;
using System.Web;
using System.Web.Routing;
using LogikBug.ModularMvc.Properties;
using LogikBug.ModularMvc.Routing;

namespace LogikBug.ModularMvc
{
	public class ModularHttpContext : HttpContextWrapper
	{
		#region Fields

		private static readonly IDictionary<object, ModularHttpContext> Registry = new Dictionary<object, ModularHttpContext>();

		#endregion

		#region Constructors

		internal ModularHttpContext()
			: this(HttpContext.Current)
		{
		}

		internal ModularHttpContext(HttpContext context)
			: base(context)
		{
		}

		public ModularHttpContext(HttpContext context, IModule module)
			: base(context)
		{
			Key = new object();
			Module = module;
			RegisterContext(this);
		}

		#endregion

		#region Properties

		public object Key { get; private set; }

		public IModule Module { get; set; }

		public static ModularHttpContext Current
		{
			get
			{
				return GetCurrentContext();
			}
		}

		#endregion

		#region Methods

		protected static ModularHttpContext GetCurrentContext()
		{
			var context = HttpContext.Current;

			if (context.Items.Contains(Resources.ModularContextSessionKey))
			{
				var key = context.Items[Resources.ModularContextSessionKey];

				if (key != null && Registry.ContainsKey(key))
				{
					return Registry[key];
				}
			}

			return new ModularHttpContext(context);
		}

		internal static ModularHttpContext Create(HttpContext httpContext)
		{
			var module = GetModuleFromRouteData(httpContext);
			return new ModularHttpContext(httpContext, module);
		}

		internal static IModule GetModuleFromRouteData(HttpContext httpContext)
		{
			var routeData = RouteTable.Routes.GetRouteData(new HttpContextWrapper(httpContext));

			if (routeData == null)
			{
				return null;
			}

			var moduleRoute = routeData.Route as ModuleRoute;
			return moduleRoute != null ? moduleRoute.Module : (routeData.Values["module"] as IModule);
		}

		public static void RegisterContext(ModularHttpContext modularContext)
		{
			if (ValidateModularContext(modularContext))
			{
				Registry[modularContext.Key] = modularContext;
				modularContext.Items[Resources.ModularContextSessionKey] = modularContext.Key;
			}
		}

		private static bool ValidateModularContext(ModularHttpContext modularContext)
		{
			return modularContext != null && modularContext.Key != null
				&& !Registry.ContainsKey(modularContext.Key)
				&& !modularContext.Items.Contains(Resources.ModularContextSessionKey);
		}

		public static void RemoveContext(object key)
		{
			if (!Registry.ContainsKey(key)) { return; }

			Registry[key].Items.Remove(key);
			Registry.Remove(key);
		}

		#endregion
	}
}